/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package me.dwk.dandan.function;

import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class ThreadVariables {
	private final Map<String, Object> variables = new HashMap<>();

	public ThreadVariables() {
	}

	/**
	 * @return the name of the currently running thread
	 */
	public String getThreadName() {
		return Thread.currentThread().getName();
	}

	/**
	 * Remove a variable.
	 *
	 * @param key
	 *            the variable name to remove
	 *
	 * @return the variable value, or {@code null} if there was no such variable
	 */
	public Object remove(String key) {
		return variables.remove(key);
	}

	/**
	 * Creates or updates a variable with a String value.
	 *
	 * @param key
	 *            the variable name
	 * @param value
	 *            the variable value
	 */
	public void put(String key, String value) {
		variables.put(key, value);
	}

	/**
	 * Creates or updates a variable with a value that does not have to be a String.
	 *
	 * @param key
	 *            the variable name
	 * @param value
	 *            the variable value
	 */
	public void putObject(String key, Object value) {
		variables.put(key, value);
	}

	/**
	 * Updates the variables with all entries found in the {@link Map} {@code vars}
	 *
	 * @param vars
	 *            map with the entries to be updated
	 */
	public void putAll(Map<String, ?> vars) {
		variables.putAll(vars);
	}

	/**
	 * Updates the variables with all entries found in the variables in {@code vars}
	 *
	 * @param vars
	 *            {@link ThreadVariables} with the entries to be updated
	 */
	public void putAll(ThreadVariables vars) {
		putAll(vars.variables);
	}

	/**
	 * Gets the value of a variable, converted to a String.
	 *
	 * @param key
	 *            the name of the variable
	 * @return the value of the variable or a toString called on it if it's non
	 *         String, or {@code null} if it does not exist
	 */
	public String get(String key) {
		Object o = variables.get(key);
		if (o instanceof String)
			return (String) o;
		else if (o != null)
			return o.toString();
		else
			return null;
	}

	/**
	 * Gets the value of a variable (not converted to String).
	 *
	 * @param key
	 *            the name of the variable
	 * @return the value of the variable, or {@code null} if it does not exist
	 */
	public Object getObject(String key) {
		return variables.get(key);
	}

	/**
	 * Gets a read-only Iterator over the variables.
	 *
	 * @return the iterator
	 */
	public Iterator<Entry<String, Object>> getIterator() {
		return Collections.unmodifiableMap(variables).entrySet().iterator();
	}

	/**
	 * @return an unmodifiable view of the entries contained in
	 *         {@link ThreadVariables}
	 */
	public Set<Entry<String, Object>> entrySet() {
		return Collections.unmodifiableMap(variables).entrySet();
	}
}
